feat(hive): HiveSignOperations — parsed generic op signing (vote/post/custom_json)#307
Merged
Merged
Conversation
…g, unblocks vote/post/custom_json
P4 phase 1: the host serializes the Graphene transaction; firmware parses
the bytes, clear-signs the ops it recognizes (vote 0, comment 1,
custom_json 18), and refuses everything else. No blind-sign fallback.
Everything displayed is re-derived from the bytes being signed.
Parser (hive.c):
- bounded LEB128 (max 5 bytes, fits uint32, overlong rejected)
- field caps per hived: names 1..16, permlinks 1..256, cj id 1..32,
vote weight int16 in [-10000,10000]
- op types 2/9/10 PERMANENTLY excluded: transfer keeps the dedicated
HiveSignTx display path; account ops keep the device-derived-keys-only
invariant (a raw-bytes path would let a host slip third-party
authorities into an account_update)
- op count 1..4, extensions must be empty, trailing bytes rejected
- tier detection: vote/comment/cj-posting = posting; cj with
required_auths = active; mixed tiers rejected as malformed (one
signature cannot satisfy both post-HF28)
Handler (fsm_msg_hive.h):
- dedicated {posting', active'} path validator pinned to the tx tier
(memo' and owner' rejected — no Graphene op uses them)
- one confirm per op + final sign confirm; uniform display rules:
explicit (+N more) truncation markers, non-ASCII slices fall back to
byte-count + hex preview
- digest SHA256(chain_id || serialized_tx) identical to HiveSignTx,
hashed straight from the decoded message (no 2KB stack copy)
len==12 (header + op_count + extensions varints) now falls through to the specific 'op count must be 1-4' error instead of the generic too-short reject; op bodies are bounds-checked as they parse. Behavior-equivalent for security — pure error-message accuracy. Formatting: clang-format 20 (CI version) over the two files the lint job flagged.
ae9ff6e to
767276d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements P4 phase 1 from
handoff-hive-sign-operations.md(review-clean revision): the host serializes the Graphene transaction; firmware parses the bytes, clear-signs the ops it recognizes, and refuses everything else — no blind-sign fallback. With #306 (login) this makes SkateHive fully usable: login → vote → post → snap; custom_json also covers Hive Engine and Splinterlands.Stacked on #306 (
feat/hive-sign-message), which stacks on #305. Merge order: #305 → #306 → this; GitHub retargets bases automatically.Message types: 1616/1617
HiveSignOperations(address_n, chain_id ≤32, serialized_tx ≤2048) /HiveSignedOperations(signature). Digest isSHA256(chain_id ‖ serialized_tx)— identical toHiveSignTx, reusing the existing signing path, hashed straight from the decoded message (no 2KB stack copy).Parser (phase-1 table: vote 0, comment 1, custom_json 18)
HiveSignTxdisplay path; account_create/update keep the device-derived-keys-only invariant — a generic raw-bytes path would let a host slip third-party authorities into an account_updateRole enforcement (dedicated validator — NOT the signBuffer one)
{posting', active'}only, pinned to the tx tier: vote/comment/cj-with-posting-auths → posting'; cj withrequired_auths→ active'. memo' (legitimate for signBuffer, meaningless for Graphene ops) and owner' are rejected. Mixed-tier transactions are rejected as malformed — one signature cannot satisfy posting + active tiers post-HF28 — as is a custom_json carrying both auth arrays.Display (uniform rules from the #306 finding-1 review)
One confirm per op + a final "Sign N Hive operation(s) with the {role} key?" confirm. Every truncated field carries an explicit
(+N more)marker; any slice containing non-ASCII (comment bodies are arbitrary UTF-8) falls back to byte-count + hex preview instead of garbling partial multi-byte sequences. Vote weight shown with two decimals (50.50%,Downvotefor negative).Pins
deps/device-protocol→f0b4549(feat/hive-sign-operations, only the two new messages)deps/python-keepkey→15d95ec:hive.sign_operations(), wire mapping, pb2 regen (pinned protoc 3.5.1), and a test-owned Graphene mini-serializer so parser and serializer bugs can't cancel outVerification
Storage.StorageRoundTripmacOS-ARM64 golden artifact; Linux CI is authoritative)make kkfirmwareclean; zeropb_callback_tin generated nanopbDownstream (per the handoff, same-day once this lands)
hdwallet shim → vault
POST /hive/sign-operations(+ ~80-line TS serializer) → Pioneerbroadcast-ops(built, PR coinmastersguild/pioneer#170, deploy pending) → extension un-stubsrequestVote/requestPost/requestCustomJson/requestBroadcast-subset. Definition of done: a KeepKey-signed vote on hiveblocks.com.